﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BartonExtension;

namespace RatingAlgorithm
{
    /*
     * Prams : cnt,timespan,avgScore,gd/bad ratio
     * Score : F(c,t,avg,g/b_r) = sigma(ai * g(c,t,avg,g/b_r))
     * Score : g(c,t,avg,g/b_r) = ln(ln(cnt) + cnt * ln(avgScore * g/b_r) + Crr(category,timespan) * cnt)
     * Score : Crr(category,timespan) = sigma(timespanInCategory)/totalTimespan
     * Score : F(c,t,avg,g/b_r) = ln(a0*ln(cnt) + a1*(cnt*ln(avgScore*g/b_r) + a2*Crr(category,timespan) *cnt);
     * */
    public class Rate
    {
        public long Clicks { get; set; }
        public double TotalScore { get; set; }
        public long GoodCount { get; set; }
        public long BadCount { get; set; }
        public long NoGdNoBd { get; set; }
        public long MaximumNumberOfDaysInCategory { get; set; }
        public long MinimumNumberOfDaysInCategory { get; set; }
        public long ClicksForMaxDays { get; set; }
        public long ClicksForMinDays { get; set; }
        public long DaysForCategory { get; set; }
        public long TotalClicksForCategory { get; set; }

        public Rate()
        { 
            
        }

        public double RateBook()
        {
            double value = Loge(0.4 * Loge(Clicks) + 
                                0.3 * (Clicks * Loge(TotalScore * G_B_Ratio())) + 
                                0.3 * CoorelationCo() * Clicks);
            return value;
        }

        public double CoorelationCo()
        {
            double rMax = ClicksForMaxDays / MaximumNumberOfDaysInCategory;
            double rMin = ClicksForMinDays / MinimumNumberOfDaysInCategory;
            double rCategory = TotalClicksForCategory / DaysForCategory;
            return .5 * (rMax + rMin) / rCategory;
        }

        public double G_B_Ratio()
        {
            return 0.4 * (GoodCount / BadCount) +
                   0.2 * (NoGdNoBd / (NoGdNoBd + GoodCount + BadCount)) + 
                   0.2 * (GoodCount / (NoGdNoBd + GoodCount + BadCount)) +
                   0.2 * (BadCount / (NoGdNoBd + GoodCount + BadCount));
        }

        public double Loge(double value)
        {
            return Math.Log(value);
        }

        public static string RateScript(string tbName,string CategoryIdTag,string BookIdTag)
        {
            string sql = "(select " +
                         "(.4 * (select ifnull(sum(Count),1) as TotalClicks from Downloads where BookId = {2}.{0}) + " +
                         " .3 * (select ifnull(sum(Count),1) as TotalClicks from Downloads where BookId = {2}.{0}) * " +
                         " (.4 * ((select ifnull(sum(Good),1) as GoodCount from Rates where BookId = {2}.{0} and Good = 1) / (select ifnull(sum(Good),1) as GoodCount from Rates where BookId = {2}.{0} and Good = 0)) + " +
                         "  .3 * ((select ifnull(sum(Good),1) as GoodCount from Rates where BookId = {2}.{0} and Good = 1) / (select ifnull(sum(Good),1) as TotalCount from Rates where BookId = {2}.{0})) + " +
                         "  .3 * ((select ifnull(sum(Good),1) as GoodCount from Rates where BookId = {2}.{0} and Good = 0) / (select ifnull(sum(Good),1) as TotalCount from Rates where BookId = {2}.{0}))) + " +
                         "  .3 * " +
                         "    (.5 * (" +
                         "( " +
                         "select ifnull(sum(D.Count),1) as ClicksForMaxDays from Downloads D " +
                         "INNER JOIN Book B on B.ID = d.BookID " +
                         "where (julianday('now') - julianday(B.CreateTimeTag)) = (SELECT max(julianday('now') - julianday(CreateTimeTag)) from Book where CategoryId = {2}.{1}) and CategoryId = {2}.{1} " +
                         ") " +
                         "/ " +
                         "( " +
                         "select max(julianday('now') - julianday(B.CreateTimeTag)) as MaximumNumberOfDaysInCategory " +
                         "from Book B " +
                         "WHERE B.CategoryId = {2}.{1} " +
                         ") + " +
                         "( " +
                         "select ifnull(sum(D.Count),1) as ClicksForMinDays from Downloads D " +
                         "INNER JOIN Book B on B.ID = d.BookID " +
                         "where (julianday('now') - julianday(B.CreateTimeTag)) = (SELECT min(julianday('now') - julianday(CreateTimeTag)) from Book where CategoryId = {2}.{1}) and CategoryId = {2}.{1} " +
                         ") " +
                         "/ " +
                         "( " +
                         "select min(julianday('now') - julianday(B.CreateTimeTag)) as MinimumNumberOfDaysInCategory " +
                         "from Book B " +
                         "WHERE B.CategoryId = {2}.{1} " +
                         ")) " +
                         "/ ( " +
                         "( " +
                         "select ifnull(sum(D.Count),1) as TotalClicksForCategory from Downloads D " +
                         "LEFT JOIN Book B on b.ID = d.BookID " +
                         "LEFT JOIN Category C on C.ID = b.CategoryId " +
                         "where B.CategoryId = {2}.{1} " +
                         ") " +
                         "/ " +
                         "( " +
                         "SELECT (julianday('now') - julianday(CreateTimeTag)) as DaysForCategory from Category where ID = {2}.{1} " +
                         "))))) As Score";
            sql = sql.FormatWith(BookIdTag, CategoryIdTag, tbName);
            return sql;
        }
    }
}
